package com.ruoyi.framework.netty;

import cn.hutool.extra.spring.SpringUtil;
import com.ruoyi.framework.netty.properties.NettyChatProperties;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import java.util.Date;

/**
 * 运行netty服务端
 * @author zhusy
 * @since 2021/11/21
 */
@Component
public class NettyServer implements InitializingBean {

    //老板（主）线程组，负责接收新接入的客户端链接
    private EventLoopGroup bossGroup;
    //工作线程组，主要负责读写相关具体业务工作的事情
    private EventLoopGroup workerGroup;
    //netty服务端启动引导类
    private ServerBootstrap serverBootstrap;

    @Override
    public void afterPropertiesSet() throws Exception {
        //老板线程组与工作线程组如果不设置线程数大小的话，默认是CPU核数*2的数量
        bossGroup = new NioEventLoopGroup(SpringUtil.getBean(NettyChatProperties.class).getBossThread());
        workerGroup = new NioEventLoopGroup(SpringUtil.getBean(NettyChatProperties.class).getWorkerThread());
        serverBootstrap = new ServerBootstrap()
                .group(bossGroup, workerGroup)
                .option(ChannelOption.SO_BACKLOG, SpringUtil.getBean(NettyChatProperties.class).getBackLog())
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .childOption(ChannelOption.TCP_NODELAY, true)
                //设置nio模型，NioServerSocketChannel是对nio类型的链接的抽象
                .channel(NioServerSocketChannel.class)
                //工作线程处理业务工作类
                .childHandler(new NettyServerInitializer());
        bind(serverBootstrap, SpringUtil.getBean(NettyChatProperties.class).getPort());
    }

    private static void bind(final ServerBootstrap serverBootstrap, final int port) {
        serverBootstrap.bind(port).addListener(future -> {
            if (future.isSuccess()) {
                System.out.println(new Date() + ": 端口[" + port + "]绑定成功!");
            } else {
                System.err.println("端口[" + port + "]绑定失败!");
            }
        });
    }

}
